package com.gomoku

import java.net.InetAddress
import java.net.InetSocketAddress
import java.net.ServerSocket
import java.net.Socket

// 服务器
class Server: ServerSocket(), Runnable {
    private val mOnlineUsers: MutableMap<String, Client> = HashMap()    // 在线用户列表

    /**
     * 析构方法。
     */
    protected fun finalize() {
        // 关闭套接字
        try {
            super.close()
        } catch (e: Exception) {
            e.printStackTrace()
        }

        // 清空在线用户列表
        mOnlineUsers.clear()
    }

    /**
     * 处理寻找其它用户请求。
     * @param request   请求
     * @param client    客户端
     */
    private fun handleFindUsers(request: FindUsersRequest, client: Client) {
        // 创建结果
        val rivalList: MutableList<String> = ArrayList(mOnlineUsers.size)
        for ((key) in mOnlineUsers) {
            // 跳过自己的名字
            if (request.mUsername == key) {
                continue
            }
            rivalList.add(key)
        }
        val result = FindUsersResult(rivalList)

        // 发送结果
        client.sendData(result)
    }

    /**
     * 处理登录请求。
     * @param request   请求
     * @param client    客户端
     */
    private fun handleLogon(request: LogonRequest, client: Client) {
        val result: LogonResult

        // 如果已登录，则直接返回
        if (mOnlineUsers[request.mUsername] != null) {
            result = LogonResult("")
            client.sendData(result)
            return
        }

        // 保存用户
        mOnlineUsers[request.mUsername] = client

        // 创建结果
        result = LogonResult(request.mUsername)

        // 发送结果
        client.sendData(result)
    }

    /**
     * 处理协议。
     * @param pro   协议
     */
    private fun handleProtocol(pro: GomokuProtocol) {
        // 如果目标用户不在线则返回
        val rivalUser = mOnlineUsers[pro.mUsername] ?: return

        // 发送给目标用户
        rivalUser.sendData(pro)
    }

    /**
     * 处理退出游戏请求。
     * @param request   请求
     * @param client    客户端
     */
    private fun handleQuitGame(request: QuitGame, client: Client) {
        // 广播该用户的请求
        for ((_, value) in mOnlineUsers) {
            value.sendData(request)
        }

        // 将该用户从在线列表移除
        mOnlineUsers.remove(request.mUsername)

        // 关闭客户端
        try {
            client.close()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * 处理客户端发送来的数据。
     * @param pro       协议
     * @param client    客户端
     */
    @Synchronized
    fun onGetMessageFromClient(pro: GomokuProtocol, client: Client) {
        when (pro.mType) {
            GomokuProtocol.Type.FIND_USERS -> this.handleFindUsers(pro as FindUsersRequest, client)
            GomokuProtocol.Type.LOGON -> this.handleLogon(pro as LogonRequest, client)
            GomokuProtocol.Type.QUIT_GAME -> this.handleQuitGame(pro as QuitGame, client)
            else -> this.handleProtocol(pro)
        }
    }

    /**
     * 接受客户端连接的线程。
     */
    override fun run() {
        var clientSocket: Socket?
        while (!super.isClosed()) {
            try {
                clientSocket = super.accept()
                Client(this, clientSocket).start()
            } catch (e: Exception) {
                break
            }
        }
    }

    /**
     * 开启服务。
     * @return 成功则返回 true，否则返回 false
     */
    fun start(): Boolean {
        // 绑定 IP 地址和端口号
        try {
            val inetAddress = InetAddress.getByName(GomokuProtocol.SERVER_IP)
            val serverAddr = InetSocketAddress(inetAddress, GomokuProtocol.SERVER_PORT)
            super.bind(serverAddr)
        } catch (e: Exception) {
            return false
        }

        // 开启接收数据的线程
        Thread(this).start()

        return true
    }
}
